<template>
  <div class="goods-sku">
    <dl v-for="(item,index) in specs" :key="index">
      <dt>{{item.name}}</dt>
      <dd>
        <template v-for="(tag,i) in item.values" :key="i">
          <img :class='{disabled: tag.disabled,selected: tag.selected}' v-if="tag.picture" :src="tag.picture" alt="" @click='toggle(tag, item.values)'>
          <span v-else :class='{disabled: tag.disabled,selected: tag.selected}' @click='toggle(tag, item.values)'>{{tag.name}}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import powerSet from '@/vendor/power-set.js'
const spliter = '#'

// 封装一个函数：生成路径字典---------------------------------------
const usePathMap = (skus) => {
  const result = {} // 字典结果数据

  // 步骤:
  // 1.获取有效sku信息
  // 2.计算每一种sku的笛卡尔集
  // 3.把笛卡尔集合并生成字典
  // console.log(skus)

  skus.forEach(sku => {
    // 1.获取有效sku信息**********************************
    // 过滤无效的（没有库存）sku信息   没有库存直接停止
    if (sku.inventory === 0) return
    // 获取有库存的sku的规格集合 转换格式为:   specSet = [蓝色, 中国, 10cm]
    const specSet = sku.specs.map(item => item.valueName)

    // 2.计算每一种sku的笛卡尔集*********************************
    // 计算每一个集合的笛卡尔集（二维数组:这里用的网上复制现成的代码,封装函数了,直接调用
    const subSets = powerSet(specSet)

    // 3基于笛卡尔集生成路径字典**********************************
    // 需要把笛卡尔集中的每一项数据拼接为一个字符串作为key添加到路径字典中(key就是属性名)
    subSets.forEach(item => {
      // 排除空集
      if (item.length === 0) return
      // 拼接路径的key: pathKey = '蓝色#日本'
      const pathKey = item.join(spliter)

      if (result[pathKey]) { // 因为pathKey是变量,所以添加对象属性 值 需要 对象名[变量]
        // 已经存在该key, 给当前的sku id添加进去(表示,符合key属性名(属性名就是笛卡尔集)包括了哪些商品)
        result[pathKey].push(sku.id) // 给对象添加 属性名为笛卡尔集的变量名里面的数组里添加值
      } else {
        // 尚不存在
        result[pathKey] = [sku.id] // 直接给 对象添加 属性名为笛卡尔集的变量名添加个新数组
      }
    })
  })

  console.log(result)
  return result
}

// 初始化的时候，判断每一个标签是否应该被禁用---------------------------------
const initCheckSpecStatus = (specs, pathMap) => {
  // 遍历每一种规格
  specs.forEach(item => {
    item.values.forEach(tag => {
      // 判断规格是否在路径字典中存在，如果不存在应该被禁用
      // 如果该规格不在路径字典中，添加一个属性disabled，值为true
      // 通过pathMap[tag.name]在词典里取值,如果没有,但会的就是假,则需要取反赋值给tag.disabled为真, 这样就添加了不可选项class类名
      tag.disabled = !pathMap[tag.name]
    })
  })
}

// 获取选中的所有的规格-------------------------------------------
// 分析:创建一空数组, 长度由有几种类别选项(不是规格), 然后顺序不能变,点击哪类了,就给当前类的选中的哪个选项就添加到数组对应的索引中, 没选中的填undefined
const useSelectedSpecs = (specs) => {
  const result = []
  specs.forEach((item, index) => { // 遍历
    // 获取每一种规格选中的对象
    const current = item.values.find(tag => tag.selected) // 再次遍历,取出符合条件的值(选中的)
    if (current) {
      // 该规格选中了，放到数组的指定位置
      result[index] = current.name
    } else {
      // 该规格没有选中，默认填充undefined
      result[index] = undefined
    }
  })
  return result
}

// 点击任意规格时，判断按钮的状态（遍历所有的规格）--------------------------------
const clickCheckSpecStatus = (specs, pathMap) => {
  // 生成路径字典
  // const pathMap = usePathMap(skus)
  specs.forEach((item, i) => {
    // 遍历：颜色、产地、尺寸
    // selectedValues = [蓝色, undefined, 10cm]
    // 这里得到的值必须是点击选中的值
    const selectedValues = useSelectedSpecs(specs)
    item.values.forEach(tag => {
      if (tag.selected) {
        // 如果标签本身就是选中的，那么不需要判断禁用状态
        return
      } else {
        // 把没有选中的规格组合进去进行判断(判断所有规格的组合情况)
        selectedValues[i] = tag.name
      }

      // 过滤出有效值（选中的值）
      const validValues = selectedValues.filter(item => item)
      if (validValues.length > 0) {
        // 需要把选中的值组合成一个pathKey: 蓝色#10cm
        const pathKey = validValues.join(spliter)
        // 判断当前选中的值，是否在有效的路径字典中
        tag.disabled = !pathMap[pathKey]
      }
    })
  })
}

// 根据skuId控制规格的默认选中
const useDefaultSelectedSpec = (skuId, skus, specs) => {
  // skuId 表示要购买的商品的skuId
  // skus 表示后端返回的所有的sku信息
  // specs 表示遍历出来的所有的规格信息

  // 获取所有需要选中的规格：[蓝色 中国 10cm]
  const currentSku = skus.find(item => item.id === skuId)
  const targetSpec = currentSku.specs.map(item => item.valueName)
  // 思路：遍历每一个规格标签，判断是否需要被选中
  specs.forEach(item => {
    item.values.forEach(tag => {
      // 判断每个规格是否要被选中
      if (targetSpec.includes(tag.name)) {
        tag.selected = true
      }
    })
  })
}

export default {
  name: 'GoodsSku',
  props: {
    skuId: {
      type: String,
      default: ''
    },
    skus: {
      type: Array,
      default: () => []
    },
    specs: {
      type: Array,
      default: () => []
    }
  },
  setup (props, { emit }) {
    // 调用路径字典
    const pathMap = usePathMap(props.skus)
    // console.log(pathMap)

    // 控制工具skuId选中默认规格
    if (props.skuId) {
      useDefaultSelectedSpec(props.skuId, props.skus, props.specs)
    }

    // 初始化时，检测标签的状态
    initCheckSpecStatus(props.specs, pathMap)

    // 控制规格选项的选中和取消
    const toggle = (tag, list) => {
      // 禁用状态的规格不可以点击
      if (tag.disabled) return

      // 需求：选中当前的选项，其他的选项需要取消选中
      // 1. 把所有的标签都取消选中
      list.forEach(item => {
        if (item !== tag) {
          // 排除当前点击的标签：其余的都取消选中
          item.selected = false
        }
      })
      // 2. 当前点击的标签单独控制
      tag.selected = !tag.selected

      // // 测试 获取选中的所有的规格
      // const ret = useSelectedSpecs(props.specs)
      // console.log(ret)

      // 点击判断每个规格的禁用状态
      clickCheckSpecStatus(props.specs, pathMap)

      // 获取选中的规格相关的结果：skuId，价格和库存相关信息
      // 判断是否所有的规格都选中了
      const sv = useSelectedSpecs(props.specs)
      if (sv.every(item => item)) {
        // 规格都选择了，获取规格相关信息
        // 使用选中的规格拼接一个路径key
        const pathKey = sv.join(spliter)
        // 获取当前购买商品的skuId
        const skuId = pathMap[pathKey][0]
        // 根据skuId获取商品信息
        const info = props.skus.find(item => item.id === skuId)
        console.log('513135')

        // let specText = ''
        // info.specs.forEach(item => {
        //   specText += `${item.name}：${item.valueName} `
        // })

        const specText = info.specs.reduce((result, item) => result + `${item.name}：${item.valueName} `, '')

        // 选中规格后的商品信息
        const skuInfo = {
          skuId: skuId,
          oldPrice: info.oldPrice,
          price: info.price,
          inventory: info.inventory,
          specText: specText
        }
        // 把这个信息传递给父组件
        emit('sku-Info', skuInfo)
      } else {
        // 没有全部选中
        emit('sku-Info', null)
      }
    }
    return { toggle }
  }
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
